package cn.windy.samary.module.abstracts.service.impl;

import cn.windy.samary.module.abstracts.service.IAbstractService;
import cn.windy.samary.module.admin.common.UserLine;
import cn.windy.samary.utils.BaseMapper;
import cn.windy.samary.utils.ShiroUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.session.RowBounds;
import org.n3r.idworker.Sid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import javax.persistence.Id;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author zyl
 * @date 2018-05-26 9:13
 */

public class AbstractServiceImpl<T> implements IAbstractService<T> {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private BaseMapper<T> baseMapper;
    @Resource
    private Sid sid;

    private Class<?> clazz;

    private Class<?> getEntityClass() {
        if (clazz == null) {
            clazz = (Class<?>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        }
        return clazz;
    }

    @Override
    public int insert(T t) {
        try {
            preInsert(t);
            return baseMapper.insert(t);
        } catch (ReflectiveOperationException e) {
            logger.error("插入数据异常！", e);
        }
        return 0;
    }

    @Override
    public int insertSelective(T t) {
        try {
            preInsert(t);
            return baseMapper.insertSelective(t);
        } catch (ReflectiveOperationException e) {
            logger.error("插入数据异常！", e);
        }
        return 0;
    }

    /**
     * id自增时可用
     *
     * @param list
     * @return
     */
    @Override
    public int insertList(List<T> list) {
        try {
            for (T t : list) {
                preInsert(t);
            }
            return baseMapper.insertList(list);
        } catch (ReflectiveOperationException e) {
            logger.error("插入数据异常！", e);
        }
        return 0;
    }


    @Override
    public int insertUseGeneratedKeys(T t) {
        try {
            preInsert(t);
            return baseMapper.insertUseGeneratedKeys(t);
        } catch (ReflectiveOperationException e) {
            logger.error("插入数据异常！", e);
        }
        return 0;
    }

    @Override
    public int updateByPrimaryKey(T t) {
        try {
            preUpdate(t);
            return baseMapper.updateByPrimaryKey(t);
        } catch (ReflectiveOperationException e) {
            logger.error("更新数据异常！", e);
        }
        return 0;
    }

    @Override
    public int updateByPrimaryKeySelective(T t) {
        try {
            preUpdate(t);
            return baseMapper.updateByPrimaryKeySelective(t);
        } catch (ReflectiveOperationException e) {
            logger.error("更新数据异常！", e);
        }
        return 0;
    }

    @Override
    public int updateByExample(T t, Object o) {
        try {
            preUpdate(t);
            return baseMapper.updateByExample(t, o);
        } catch (ReflectiveOperationException e) {
            logger.error("更新数据异常！", e);
        }
        return 0;
    }

    @Override
    public int updateByExampleSelective(T t, Object o) {
        try {
            preUpdate(t);
            return baseMapper.updateByExampleSelective(t, o);
        } catch (ReflectiveOperationException e) {
            logger.error("更新数据异常！", e);
        }
        return 0;
    }

    @Override
    public int deleteByPrimaryKey(Object o) {
        return baseMapper.deleteByPrimaryKey(o);
    }

    @Override
    public int deleteByPrimaryKeys(List<String> primaryKeys) {
        Example example = new Example(getEntityClass());
        Example.Criteria criteria = example.createCriteria();
        criteria.andIn("id", primaryKeys);
        return baseMapper.deleteByExample(example);
    }

    @Override
    public int delete(T t) {
        return baseMapper.delete(t);
    }

    @Override
    public int deleteByExample(Object o) {
        return baseMapper.deleteByExample(o);
    }

    @Override
    public List<T> selectByExample(Object o) {
        return baseMapper.selectByExample(o);
    }

    @Override
    public List<T> selectAll() {
        return baseMapper.selectAll();
    }

    @Override
    public T selectByPrimaryKey(Object o) {
        return baseMapper.selectByPrimaryKey(o);
    }

    @Override
    public int selectCount(T t) {
        return baseMapper.selectCount(t);
    }

    @Override
    public List<T> select(T t) {
        return baseMapper.select(t);
    }

    @Override
    public T selectOne(T t) {
        return baseMapper.selectOne(t);
    }

    @Override
    public int selectCountByExample(Object o) {
        return baseMapper.selectCountByExample(o);
    }

    @Override
    public T selectOneByExample(Object o) {
        return baseMapper.selectOneByExample(o);
    }

    @Override
    public List<T> selectByExampleAndRowBounds(Object o, RowBounds rowBounds) {
        return baseMapper.selectByExampleAndRowBounds(o, rowBounds);
    }

    @Override
    public List<T> selectByRowBounds(T t, RowBounds rowBounds) {
        return baseMapper.selectByRowBounds(t, rowBounds);
    }

    @Override
    public boolean existsWithPrimaryKey(Object o) {
        return baseMapper.existsWithPrimaryKey(o);
    }

    /**
     * 插入数据之前设置id ,create_time
     *
     * @return id
     */
    private String preInsert(T entity) throws ReflectiveOperationException {
        Method getIdMethod = null;
        Method setTimeMethod = null;
        Method setCreateUserMethod = null;
        Method getTimeMethod = null;
        Method getCreateUserMethod = null;
        Class<?> entityClass = getEntityClass();
        String setKeyMethodName = "setId";
        String getKeyMethodName = "getId";
        try {
            getIdMethod = entityClass.getMethod(getKeyMethodName);
        } catch (NoSuchMethodException e) {
            Field field = getKeyField(entityClass);
            if (field != null) {
                String fieldName = field.getName();
                String upperCase = upperCase(fieldName);
                getKeyMethodName = "get" + upperCase;
                setKeyMethodName = "set" + upperCase;
                getIdMethod = entityClass.getMethod(getKeyMethodName);
            }
        }
        try {
            getTimeMethod = entityClass.getMethod("getCreateTime");
            Object createTime = getTimeMethod.invoke(entity);
            if (createTime == null) {
                setTimeMethod = entityClass.getMethod("setCreateTime", Date.class);
                setTimeMethod.invoke(entity, new Date());
            }
        } catch (NoSuchMethodException e) {
            logger.warn("preInsert————获取或设置创建时间异常", e.getMessage());
        }
        try {
            getCreateUserMethod = entityClass.getMethod("getCreateUser");
            String userId = (String) getCreateUserMethod.invoke(entity);
            if (StringUtils.isBlank(userId)) {
                setCreateUserMethod = entityClass.getMethod("setCreateUser", String.class);
                UserLine user = ShiroUtils.getUserLine();
                if (user != null) {//已经登陆
                    setCreateUserMethod.invoke(entity, user.getId());
                }
            }
        } catch (NoSuchMethodException e) {
            logger.warn("preInsert————获取或设置创建用户异常", e.getMessage());
        }
        String id = null;
        if (getIdMethod != null) {
            id = (String) getIdMethod.invoke(entity);
            if (StringUtils.isEmpty(id)) {
                Method setIdMethod = entityClass.getMethod(setKeyMethodName, String.class);
                id = sid.nextShort();
                setIdMethod.invoke(entity, id);
            }
        }
        return id;
    }

    /**
     * 更新数据之前设置update_time
     */
    private void preUpdate(T entity) throws ReflectiveOperationException {
        Method setTimeMethod = null;
        Method setUpdateUserMethod = null;
        Method getTimeMethod = null;
        Method getUpdateUserMethod = null;
        Class<?> entityClass = getEntityClass();
        try {
            getTimeMethod = entityClass.getMethod("getUpdateTime");
            Object updateTime = getTimeMethod.invoke(entity);
            if (updateTime == null) {
                setTimeMethod = entityClass.getMethod("setUpdateTime", Date.class);
                setTimeMethod.invoke(entity, new Date());
            }
        } catch (NoSuchMethodException e) {
            logger.warn("preUpdate————获取或设置更新时间异常", e.getMessage());
        }
        try {
            getUpdateUserMethod = entityClass.getMethod("getUpdateUser");
            String updateUserId = (String) getUpdateUserMethod.invoke(entity);
            if (StringUtils.isBlank(updateUserId)) {
                setUpdateUserMethod = entityClass.getMethod("setUpdateUser", String.class);
                UserLine user = ShiroUtils.getUserLine();
                if (user != null) {
                    //已经登陆
                    setUpdateUserMethod.invoke(entity, user.getId());
                }
            }
        } catch (NoSuchMethodException e) {
            logger.warn("preUpdate————获取或设置更新用户异常", e.getMessage());
        }
    }

    /**
     * 获取实体类主键属性字段，根据Id注解进行区分
     * 只对单Id注解有效，对于无Id注解或多Id注解，返回null
     *
     * @param clazz clazz
     * @return 属性
     */
    private Field getKeyField(Class<?> clazz) {
        Field[] declaredFields = clazz.getDeclaredFields();
        List<Field> fields = new ArrayList<>();
        for (Field field : declaredFields) {
            Id declaredAnnotation = field.getAnnotation(Id.class);
            if (declaredAnnotation != null) {
                fields.add(field);
            }
        }
        return fields.size() != 1 ? null : fields.get(0);
    }

    private String upperCase(String str) {
        char[] ch = str.toCharArray();
        if (ch[0] >= 'a' && ch[0] <= 'z') {
            ch[0] = (char) (ch[0] - 32);
        }
        return new String(ch);
    }
}
